package com.sgy.nio.selector;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

public class NIOSelectorServer {

    public static void main(String[] args) throws IOException {
        // 打开一个服务端通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 绑定对应的端口号
        serverSocketChannel.bind(new InetSocketAddress(9999));

        // 设置通道为非阻塞
        serverSocketChannel.configureBlocking(false);

        // 创建选择器
        Selector selector = Selector.open();

        // 将服务端通道注册到选择器上，并指定监听事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务端启动成功...");

        while (true) {
            // 检查选择器上是否有事件
            int select = selector.select(2000);
            if (select == 0) {
                System.out.println("没有事件发生...");
                continue;
            }
            // 获取事件集合
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // 判断是否是客户端连接事件
                if (key.isAcceptable()) {
                    // 得到客户端通道，并将客户端通道注册到选择器上，并指定监听事件
                    try {
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        System.out.println("有客户端连接...");

                        // 将通道设置为非阻塞状态
                        socketChannel.configureBlocking(false);
                        socketChannel.register(selector, SelectionKey.OP_READ);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }

                // 判断是否是客户端读就绪事件
                if (key.isReadable()) {
                    // 得到客户端通道，读取数据到缓冲区
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    try {
                        int read = socketChannel.read(byteBuffer);
                        if (read > 0) {
                            System.out.println("客户端消息：" + new String(byteBuffer.array(), 0, read, StandardCharsets.UTF_8));
                            // 给客户端回写数据
                            socketChannel.write(ByteBuffer.wrap("hello client".getBytes(StandardCharsets.UTF_8)));
                            socketChannel.close();
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }

                // 从集合中删除对应事件，防止二次处理
                iterator.remove();
            }
        }
    }
}
